home *** CD-ROM | disk | FTP | other *** search
/ Personal Paint 7.1 / Cloanto Personal Paint v7.1.iso / utilities / developer_docs / personal_io / source / pbm / personal_pbm_io.c next >
Encoding:
C/C++ Source or Header  |  1996-06-02  |  21.0 KB  |  885 lines

  1.  
  2. /*
  3. **  $VER: personal_pbm_io.c 5.0 (20.02.96)
  4. **
  5. **  C source for personal_pbm_io.library.
  6. **  SAS/C source code.
  7. **
  8. **  Copyright ⌐ 1996 Cloanto Italia srl
  9. **        All Rights Reserved
  10. */
  11.  
  12. #include <exec/types.h>
  13. #include <libraries/personal_io.h>
  14. #include <string.h>
  15.  
  16. /*
  17.  *  pragma aliases
  18.  */
  19. #define SysBase picinfo->SysBase
  20. #define DOSBase picinfo->DOSBase
  21. #define GfxBase picinfo->GfxBase
  22. #define IntuitionBase picinfo->IntuitionBase
  23. #define IconBase picinfo->IconBase
  24.  
  25. static UBYTE VersionStr[] = "$VER:Personal PBM IO Library 5.0 (20.02.96)";
  26.  
  27. /*
  28.  *  The PBM library just supports one picture type
  29.  */
  30. #define DATA_PBM  0
  31. #define DATA_NUM  1
  32.  
  33. static struct DataInfoEntry DInfo[DATA_NUM] =
  34. {
  35.    {
  36.     DATA_PBM,    /* PBM picture type code */
  37.     DIF_LOAD    /* attr: planar images images can be loaded */
  38.     | DIF_LOAD_24    /* attr: 24bit chunky images can be loaded */
  39.     | DIF_SAVE    /* attr: planar images can be saved
  40.                        (converted to 24bit PBM data, if required) */
  41.     | DIF_LOADFILE    /* attr: the data is read from file */
  42.     | DIF_SAVEFILE    /* attr: the data is written to file */
  43.     | DIF_RECOGNIZE /* attr: PBM files can be recognized */
  44.     | DIF_SAVEOPTS, /* attr: there are options for WritePicture() */
  45.     PCDT_FORMAT    /* data: image format */
  46.     | PCDT_IMAGE    /* data: image bitmap */
  47.     | PCDT_PALETTE, /* data: color palette (PBM/PGM images) */
  48.     450,        /* sort priority */
  49.     "PBM",        /* full name */
  50.     "PBM",        /* short name */
  51.     { ".pbm", ".pgm", ".ppm" }    /* file name suffixes */
  52.    }
  53. };
  54. static LONG DataCount;    /* counter used by query functions */
  55.  
  56. /*
  57.  *  PBM Options
  58.  *
  59.  *  AUTO: if 0, 24-bit data is always saved,
  60.  *        if 1, based on the image being saved,
  61.  *        B/W or gray-level or 24bit data is saved.
  62.  *
  63.  *  BINARY: if 0, ASCII PBM files are saved
  64.  *          if 1, binary PBM files are saved.
  65.  */
  66. #define PBM_OPT_AUTO    0
  67. #define PBM_OPT_BINARY  1
  68. #define PBM_OPTIONS_NUM 2
  69.  
  70. static struct DataOptionEntry PbmOptions[PBM_OPTIONS_NUM] =
  71. {
  72.    {
  73.     DOT_BOOL,    /* Type */
  74.     "AUTO",        /* Name */
  75.     DOUI_AUTO,    /* UITextStr */
  76.     0,        /* Flags: WritePicture() option */
  77.     1,        /* Value */
  78.     0, 1, 1,    /* Min, Max, Default */
  79.     ""    },    /* String */
  80.    {
  81.     DOT_BOOL,    /* Type */
  82.     "BINARY",    /* Name */
  83.     DOUI_BINARY,    /* UITextStr */
  84.     0,        /* Flags: WritePicture() option */
  85.     1,        /* Value */
  86.     0, 1, 1,    /* Min, Max, Default */
  87.     ""    }    /* String */
  88. };
  89.  
  90. /* data used by the option query functions */
  91.  
  92. static struct DataOptionEntry *Options[DATA_NUM] = { PbmOptions };
  93. static LONG DataOptionMax[DATA_NUM] = { PBM_OPTIONS_NUM-1 };
  94. static LONG DataOptionCount[DATA_NUM];
  95.  
  96. /*
  97.  *  library interface protos
  98.  */
  99. __asm BOOL __saveds GetFirstDataInfo(register __a0 struct DataInfo *);
  100. __asm BOOL __saveds GetNextDataInfo(register __a0 struct DataInfo *);
  101. __asm WORD __saveds GetPictureInfo(register __a0 struct PictureInfo *);
  102. __asm LONG __saveds GetProgressBumps(register __a0 struct PictureInfo *);
  103. __asm WORD __saveds ReadPicture(register __a0 struct PictureInfo *);
  104. __asm WORD __saveds WritePicture(register __a0 struct PictureInfo *);
  105. __asm void __saveds IOLibCleanup(register __a0 struct PictureInfo *);
  106. __asm BOOL __saveds GetFirstOption(register __a0 struct DataInfo *, register __a1  struct DataOption *);
  107. __asm BOOL __saveds GetNextOption(register __a0 struct DataInfo *, register __a1  struct DataOption *);
  108. __asm void __saveds SetOption(register __a0 struct DataInfo *, register __a1  struct DataOption *);
  109. __asm void __saveds ResetOptions(register __a0 struct DataInfo *);
  110. __asm WORD __saveds PersonalIOPrivate1(void);
  111. __asm WORD __saveds PersonalIOPrivate2(void);
  112. __asm WORD __saveds PersonalIOPrivate3(void);
  113.  
  114. /*
  115.  *  library's standard static protos
  116.  */
  117. static void GetDataInfo(struct DataInfo *, LONG);
  118. static void GetDataOption(struct DataOption *, struct DataOptionEntry *);
  119. static BOOL Handshake(struct DataInfo *);
  120.  
  121. /*
  122.  *  PBM-specific protos
  123.  */
  124. static int GetFileNum(struct PictureInfo *);
  125. static UBYTE *SkipBlank(UBYTE *);
  126. static BOOL WriteFileNum(int, struct PictureInfo *);
  127.  
  128. /*
  129.  *  PBM subtypes
  130.  */
  131. #define PBM_ASCII  0  /* "P1" - portable bitmap (B/W, ASCII) */
  132. #define PGM_ASCII  1  /* "P2" - portable graymap (gray levels, ASCII) */
  133. #define PPM_ASCII  2  /* "P3" - portable pixmap (24 bit, ASCII) */
  134. #define PBM_BINARY 3  /* "P4" - portable bitmap (B/W, binary) */
  135. #define PGM_BINARY 4  /* "P5" - portable graymap (gray levels, binary) */
  136. #define PPM_BINARY 5  /* "P6" - portable pixmap (24 bit, binary) */
  137. #define NO_FORMAT  -1
  138.  
  139.  
  140.  
  141.  
  142.  
  143.  
  144.  
  145.  
  146. /*
  147.  *  Standard query dispatcher:
  148.  *  the n'th DataInfoEntry is copied to 'dinfo'.
  149.  *
  150.  *  This function does not usually need to be changed,
  151.  *  unless the library supports run-time defined picture types.
  152.  */
  153. static void GetDataInfo(struct DataInfo *dinfo, LONG n)
  154. {
  155.     struct DataInfoEntry *de = &DInfo[n];
  156.     LONG s;
  157.  
  158.     dinfo->Code = de->Code;
  159.     dinfo->Flags = de->Flags;
  160.     dinfo->ProcessData = de->ProcessData;
  161.     dinfo->Priority = de->Priority;
  162.     strcpy(dinfo->Name, de->Name);
  163.     strcpy(dinfo->ShortName, de->ShortName);
  164.  
  165.     for (s = 3; --s >= 0; )
  166.     {
  167.         if (de->FileSuffix[s])
  168.             strcpy(&dinfo->FileSuffix[s][0], de->FileSuffix[s]);
  169.         else
  170.             dinfo->FileSuffix[s][0] = 0;
  171.     }
  172.     memset(dinfo->pad, 0, sizeof(dinfo->pad));
  173. }
  174.  
  175. /*
  176.  *  Standard handshake function:
  177.  *  FALSE is returned if handshaking fails,
  178.  *  TRUE if it succeeds.
  179.  */
  180. static BOOL Handshake(struct DataInfo *dinfo)
  181. {
  182.     /*
  183.      * Cloanto is a registered trademark of Cloanto Italia srl;
  184.      * use of the following handshaking protocol requires a license,
  185.      * which is normally available at no charge for non-commercial use.
  186.          */
  187.     static UBYTE hs_text[] = "Cloanto«";
  188.  
  189.     if (dinfo->Version >= 5)  /* V5 of client interface feature */
  190.     {
  191.         if (dinfo->HandshakeText == NULL)
  192.             return(FALSE);
  193.         if (strcmp(dinfo->HandshakeText, hs_text) != 0)
  194.             return(FALSE);
  195.         /*
  196.          * the library internal string is passed
  197.          */
  198.         dinfo->HandshakeText = hs_text;
  199.     }
  200.     return(TRUE);
  201. }
  202.  
  203. /*
  204.  *  Standard query function
  205.  *  (support for multiple picture types is included)
  206.  */
  207. __asm BOOL __saveds GetFirstDataInfo(register __a0 struct DataInfo *dinfo)
  208. {
  209.     if (Handshake(dinfo))
  210.     {
  211.         DataCount = 0;
  212.         if (DataCount < DATA_NUM)
  213.         {
  214.             GetDataInfo(dinfo, DataCount++);
  215.             return(TRUE);
  216.         }
  217.     }
  218.     return(FALSE);
  219. }
  220.  
  221. /*
  222.  *  Standard query function
  223.  *  (support for multiple picture types is included)
  224.  */
  225. __asm BOOL __saveds GetNextDataInfo(register __a0 struct DataInfo *dinfo)
  226. {
  227.     if (Handshake(dinfo))
  228.     {
  229.         if (DataCount < DATA_NUM)
  230.         {
  231.             GetDataInfo(dinfo, DataCount++);
  232.             return(TRUE);
  233.         }
  234.     }
  235.     return(FALSE);
  236. }
  237.  
  238. /*
  239.  *  This function skips comments and blank characters
  240.  */
  241. static UBYTE *SkipBlank(UBYTE *ptr)
  242. {
  243.     for (; *ptr == ' '  ||
  244.            *ptr == '\t' ||
  245.            *ptr == '\n' ||
  246.            *ptr == '\r' ||
  247.            *ptr == '#' ;  ptr++)
  248.     {
  249.         if (*ptr == '#')  /* skip comment */
  250.         {
  251.             for (ptr++; *ptr != '\n' && *ptr != '\r' && *ptr != 0; ptr++) ;
  252.         }
  253.     }
  254.     return(ptr);
  255. }
  256.  
  257. /*
  258.  *  File recognition function:
  259.  *  when the file has been successfully identified,
  260.  *  the image format must be returned.
  261.  */
  262. __asm WORD __saveds GetPictureInfo(register __a0 struct PictureInfo *picinfo)
  263. {
  264.     UBYTE *fh, *fh2;
  265.     WORD format, n;
  266.     int val;
  267.  
  268.     if (picinfo->Version < 3)
  269.         return(PIOERR_BADVER);
  270.     /*
  271.      *  picinfo->Data.Code is ignored: the PBM library just supports
  272.      *  one picture type.
  273.      *  Multiple type libraries must check the type code:
  274.      *  if it is DIC_ANYDATA, any library's type is OK,
  275.      *  otherwise just the specified picture type can be loaded.
  276.      */
  277.  
  278.     fh = picinfo->FileHead;
  279.     fh2 = fh + 1;
  280.  
  281.     if (*fh == 'P' && *fh2 >= '1' && *fh2 <= '6')
  282.         format = *fh2 - '1';    /* OK: it is a valid PBM file */
  283.     else
  284.         return(PIOERR_BADTYPE);    /* not a PBM file */
  285.  
  286.     GetDataInfo(&picinfo->Data, DATA_PBM);    /* give full information about this picture type */
  287.  
  288.     fh = SkipBlank(fh+2);
  289.     if ((n = stcd_i(fh, &val)) == 0)  /* get image width */
  290.         return(PIOERR_BADTYPE);
  291.     picinfo->Width = val;
  292.  
  293.     fh = SkipBlank(fh + n);
  294.     if ((n = stcd_i(fh, &val)) == 0)  /* get image height */
  295.         return(PIOERR_BADTYPE);
  296.     picinfo->Height = val;
  297.  
  298.     if (format != PBM_ASCII && format != PBM_BINARY)
  299.     {
  300.         fh = SkipBlank(fh + n);
  301.         if ((n = stcd_i(fh, &val)) == 0)  /* get maximum color-component value */
  302.             return(PIOERR_BADTYPE);
  303.         if (val == 0)
  304.             return(PIOERR_BADTYPE);
  305.         picinfo->User1 = (APTR)val;    /* it will be used later */
  306.     }
  307.     fh += n;
  308.     fh2 = SkipBlank(fh);
  309.     if ((format == PBM_BINARY || format == PGM_BINARY || format == PPM_BINARY)
  310.         && (fh2-fh) > 1)
  311.         fh2 = fh + 1;
  312.  
  313.     /*  store image data offset and image format
  314.      */
  315.     picinfo->User2 = (APTR)(fh2 - picinfo->FileHead);
  316.     picinfo->User3 = (APTR)format;
  317.  
  318.     if (format == PGM_ASCII || format == PGM_BINARY)
  319.         picinfo->Depth = 8;    /* a 256 grays image will be loaded */
  320.  
  321.     else if (format == PBM_ASCII || format == PBM_BINARY)
  322.         picinfo->Depth = 1;    /* a B/W image will be loaded */
  323.     else
  324.         picinfo->Depth = 24;    /* a true color image will be loaded */
  325.  
  326.     /*  true color images can be previewed
  327.      */
  328.     picinfo->PreviewDepth = (picinfo->Depth == 24) ? 24 : 0;
  329.  
  330.     /*  image format information has been stored
  331.      */
  332.     picinfo->ProcessedData = PCDT_FORMAT;
  333.  
  334.     return(PIOERR_OK);
  335. }
  336.  
  337. /*
  338.  *  Progress requester information function:
  339.  *  the load and save operations will issue <picture height> bumps.
  340.  */
  341. __asm LONG __saveds GetProgressBumps(register __a0 struct PictureInfo *picinfo)
  342. {
  343.     return((LONG)picinfo->Height);
  344. }
  345.  
  346. /*
  347.  *  This function gets a numeric value from an ASCII file
  348.  *  (comments are skipped).
  349.  */
  350. static int GetFileNum(struct PictureInfo *picinfo)
  351. {
  352.     UBYTE buff[80], *bp;
  353.     BOOL skip_comm, get_num;
  354.     int val;
  355.  
  356.     bp = buff;
  357.     skip_comm = get_num = FALSE;
  358.     for (;;) {
  359.         if (get_num)
  360.             ++bp;
  361.         if (!picinfo->ReadFile(bp, 1))
  362.             break;
  363.         if (skip_comm)
  364.         {
  365.             if (*bp == '\n' || *bp == '\r' || *bp == 0)
  366.                 skip_comm = FALSE;
  367.         }
  368.         else
  369.         {
  370.             if (get_num)
  371.             {
  372.                 if (*bp < '0' || *bp > '9')
  373.                     break;
  374.             }
  375.             else
  376.             {
  377.                 if (*bp != ' ' || *bp != '\t' || *bp != '\n' || *bp == '\r')
  378.                 {
  379.                     if (*bp == '#')
  380.                         skip_comm = TRUE;
  381.                     else if (*bp >= '0' && *bp <= '9')
  382.                         get_num = TRUE;
  383.                 }
  384.             }
  385.         }
  386.     }
  387.     *bp = 0;
  388.     return((int)(stcd_i(buff, &val) ? val : -1));
  389. }
  390.  
  391. /*
  392.  *  Image loading function
  393.  */
  394. __asm WORD __saveds ReadPicture(register __a0 struct PictureInfo *picinfo)
  395. {
  396.     struct Color *col;
  397.     struct BitMap *bmap;
  398.     UBYTE *r_plane, *g_plane, *b_plane, *rpl, *gpl, *bpl;
  399.     LONG  bmap_mod;
  400.     int r, g, b, maxval;
  401.     float scale;
  402.     WORD format, w, h, x, y, c;
  403.     UBYTE byte_buff;
  404.  
  405.     /*  position the file at the beginning of image data
  406.      */
  407.     if (picinfo->SeekFile(SKF_ABSOLUTE, (LONG)picinfo->User2) < 0)
  408.         return(PIOERR_FILE_ERR);
  409.  
  410.     format = (WORD)picinfo->User3;
  411.  
  412.     if (format == PBM_ASCII || format == PBM_BINARY)
  413.         maxval = 255;
  414.     else
  415.     {
  416.         maxval = (int)picinfo->User1;
  417.         if (maxval != 255)
  418.             scale = 255.0 / (float)maxval;
  419.     }
  420.  
  421.     /*  set the BINARY option using the current file information
  422.      *  (when the image will be saved again,
  423.      *   the original format will be used)
  424.      */
  425.     PbmOptions[PBM_OPT_BINARY].Value = (format == PBM_BINARY ||
  426.                         format == PGM_BINARY ||
  427.                         format == PPM_BINARY) ? 1 : 0;
  428.  
  429.     if ((picinfo->ProcessData & PCDT_PALETTE) && picinfo->Palette)
  430.     {
  431.         /* algorithmically build a B/W or a gray palette
  432.          */
  433.         col = picinfo->Palette;
  434.         if (picinfo->Depth == 8)  /* PGM: gray levels palette */
  435.         {              /* (black fading to white)  */
  436.             for (c = 0; c < 256; c++, col++)
  437.             {
  438.                 col->Red = col->Green = col->Blue = c;
  439.                 col->EFlag = 0;
  440.             }
  441.         }
  442.         else {    /* PBM: white+black palette */
  443.             col->Red = col->Green = col->Blue = 255; /* white */
  444.             col->EFlag = 0;
  445.             col++;
  446.             col->Red = col->Green = col->Blue = 0;   /* black */
  447.             col->EFlag = 0;
  448.         }
  449.         picinfo->ProcessedData |= PCDT_PALETTE; /* color palette data are now available */
  450.     }
  451.  
  452.     if ((picinfo->ProcessData & PCDT_IMAGE) && picinfo->BMap)
  453.     {
  454.         /* PCDT_IMAGE bit is set here to flag the presence
  455.          * of even partially loaded image data
  456.          * (see PIOERR_PARTIAL return code below)
  457.          */
  458.         picinfo->ProcessedData |= PCDT_IMAGE;
  459.  
  460.         w = picinfo->Width;
  461.         h = picinfo->Height;
  462.         bmap = picinfo->BMap;
  463.  
  464.         if (picinfo->Depth == 24)    /* read PBM color data */
  465.         {
  466.             r_plane = bmap->Planes[0];
  467.             g_plane = bmap->Planes[1];
  468.             b_plane = bmap->Planes[2];
  469.             bmap_mod = bmap->BytesPerRow;
  470.  
  471.             for (y = 0; y < h; y++)
  472.             {
  473.                 rpl = r_plane;
  474.                 gpl = g_plane;
  475.                 bpl = b_plane;
  476.                 for (x = 0; x < w; x++, rpl++, gpl++, bpl++)
  477.                 {
  478.                     switch (format)
  479.                     {
  480.                         case PPM_ASCII:
  481.                             r = GetFileNum(picinfo);
  482.                             g = GetFileNum(picinfo);
  483.                             b = GetFileNum(picinfo);
  484.                             break;
  485.                         case PPM_BINARY:
  486.                             r = picinfo->ReadFile(&byte_buff, 1) ? byte_buff : -1;
  487.                             g = picinfo->ReadFile(&byte_buff, 1) ? byte_buff : -1;
  488.                             b = picinfo->ReadFile(&byte_buff, 1) ? byte_buff : -1;
  489.                             break;
  490.                     }
  491.                     if (r < 0 || g < 0 || b < 0)
  492.                         return(PIOERR_PARTIAL);
  493.  
  494.                     if (maxval != 255)    /* scale to range 0...255 */
  495.                     {
  496.                         r = (float)r * scale + 0.5;
  497.                         g = (float)g * scale + 0.5;
  498.                         b = (float)b * scale + 0.5;
  499.                     }
  500.                     *rpl = r;
  501.                     *gpl = g;
  502.                     *bpl = b;
  503.                 }
  504.  
  505.                 if (picinfo->BumpProgress)  /* one more progress requester step */
  506.                 {
  507.                     if (picinfo->BumpProgress())
  508.                         return(PIOERR_CANCEL);  /* user cancelled */
  509.                 }
  510.                 if (picinfo->PreviewDepth)
  511.                     picinfo->PreviewRow(bmap, y);    /* feed one more preview row */
  512.  
  513.                 r_plane += bmap_mod;
  514.                 g_plane += bmap_mod;
  515.                 b_plane += bmap_mod;
  516.             }
  517.         }
  518.         else    /* read B/W or gray image data */
  519.         {
  520.             /*
  521.              *  planar bitmap writing initialization
  522.              */
  523.             picinfo->FastWritePix(bmap, FBMP_INIT, 0, 0);
  524.  
  525.             for (y = 0; y < h; y++)
  526.             {
  527.                 for (x = 0; x < w; x++)
  528.                 {
  529.                     switch (format)
  530.                     {
  531.                         case PGM_ASCII:
  532.                         case PBM_ASCII:
  533.                             g = GetFileNum(picinfo);
  534.                             break;
  535.                         case PGM_BINARY:
  536.                         case PBM_BINARY:
  537.                             g = picinfo->ReadFile(&byte_buff, 1) ? byte_buff : -1;
  538.                             break;
  539.                     }
  540.                     if (g < 0)
  541.                         return(PIOERR_PARTIAL);
  542.  
  543.                     if (maxval != 255)    /* scale to range 0...255 */
  544.                         g = (float)g * scale + 0.5;
  545.  
  546.                     if (format == PBM_BINARY) /* write 8 B/W pixels */
  547.                     {
  548.                         for (c = 8; c > 0 && x < w; c--, x++, g <<= 1)
  549.                             picinfo->FastWritePix(bmap, x, y, (g & 0x80) ? 1 : 0);
  550.                         x -= 1;
  551.                     }
  552.                     else    /* write 1 (gray) pixel */
  553.                         picinfo->FastWritePix(bmap, x, y, g);
  554.                 }
  555.                 /*
  556.                  *  flush pixel row buffer
  557.                  */
  558.                 picinfo->FastWritePix(bmap, FBMP_FLUSH,0,0);
  559.  
  560.                 if (picinfo->BumpProgress)  /* one more progress requester step */
  561.                 {
  562.                     if (picinfo->BumpProgress())
  563.                         return(PIOERR_CANCEL);  /* user cancelled */
  564.                 }
  565.             }
  566.         }
  567.     }
  568.     return(PIOERR_OK);
  569. }
  570.  
  571. /*
  572.  *  This function writes numeric values to an ASCII file
  573.  *  (data is formatted in order to be readable in a 80 columns display)
  574.  */
  575. static BOOL WriteFileNum(int val, struct PictureInfo *picinfo)
  576. {
  577.     #define ROW_LIMIT  (70-4)
  578.  
  579.     static WORD pos = 0;    /* position counter */
  580.     UBYTE buff[20], *b;
  581.     LONG ln;
  582.  
  583.     if (val < 0)    /* just reset position */
  584.     {
  585.         pos = 0;
  586.         return(TRUE);
  587.     }
  588.     b = buff;
  589.     if (pos != 0)
  590.         *b++ = ' ';  /* separator */
  591.  
  592.     b += stci_d(b, val);
  593.     ln = b - buff;
  594.     pos += ln;
  595.     if (!picinfo->WriteFile(buff, ln))
  596.         return(FALSE);
  597.  
  598.     if (pos >= ROW_LIMIT)    /* start a new line */
  599.     {
  600.         pos = 0;
  601.         if (!picinfo->WriteFile("\n", 1))
  602.             return(FALSE);
  603.     }
  604.     return(TRUE);
  605. }
  606.  
  607. /*
  608.  *  Image saving function
  609.  */
  610. __asm WORD __saveds WritePicture(register __a0 struct PictureInfo *picinfo)
  611. {
  612.     WORD format, n, w, h, x, y;
  613.     UBYTE buff[80], *b;
  614.     struct BitMap *bmap;
  615.     struct Color *col, *col2;
  616.  
  617.     if (picinfo->Version < 3)
  618.         return(PIOERR_BADVER);
  619.  
  620.     if ((picinfo->ProcessData & PCDT_IMAGE) == 0 ||
  621.         picinfo->BMap == NULL ||
  622.         picinfo->Palette == NULL)
  623.         return(PIOERR_OK);
  624.  
  625.     format = NO_FORMAT;
  626.  
  627.     if (PbmOptions[PBM_OPT_AUTO].Value)  /* automatic PBM/PGM/PPM detection */
  628.     {
  629.         col = picinfo->Palette;
  630.         for (n = 1 << picinfo->Depth; --n >= 0; col++)
  631.         {
  632.             if (!(col->Red == col->Green && col->Green == col->Blue))
  633.                 break;
  634.         }
  635.         if (n < 0)  /* the color palette just contains gray shades */
  636.         {
  637.             col = picinfo->Palette;
  638.             col2 = col + 1;
  639.  
  640.             if (picinfo->Depth == 1 &&
  641.                 ((col->Red == 0 && col2->Red == 255) ||
  642.                  (col->Red == 255 && col2->Red == 0)))  /* it is a B/W image */
  643.                 format = PbmOptions[PBM_OPT_BINARY].Value ? PBM_BINARY : PBM_ASCII;
  644.             else  /* it is a gray-level image */
  645.                 format = PbmOptions[PBM_OPT_BINARY].Value ? PGM_BINARY : PGM_ASCII;
  646.         }
  647.     }
  648.     if (format == NO_FORMAT)  /* default format: PPM */
  649.         format = PbmOptions[PBM_OPT_BINARY].Value ? PPM_BINARY : PPM_ASCII;
  650.  
  651.     /*
  652.      *  write file header
  653.      */
  654.     b = buff;
  655.     *b++ = 'P';
  656.     *b++ = format + '1';
  657.     *b++ = ' ';
  658.     b += stci_d(b, picinfo->Width);
  659.     *b++ = ' ';
  660.     b += stci_d(b, picinfo->Height);
  661.  
  662.     if (format != PBM_ASCII && format != PBM_BINARY)
  663.     {
  664.         *b++ = ' ';
  665.         b += stci_d(b, 255);
  666.     }
  667.     *b++ = '\n';
  668.     if (!picinfo->WriteFile(buff, b-buff))
  669.         return(PIOERR_FILE_ERR);
  670.  
  671.     WriteFileNum(-1, picinfo);  /* reset position */
  672.  
  673.     w = picinfo->Width;
  674.     h = picinfo->Height;
  675.     bmap = picinfo->BMap;
  676.  
  677.     /*
  678.      *  planar bitmap reading initialization
  679.      */
  680.     picinfo->FastReadPix(bmap, FBMP_INIT, 0);
  681.  
  682.     for (y = 0; y < h; y++)
  683.     {
  684.         for (x = 0; x < w; x++)
  685.         {
  686.             col = picinfo->Palette +
  687.                   picinfo->FastReadPix(bmap, x, y);
  688.  
  689.             switch (format) {
  690.                 case PBM_ASCII:
  691.                     if (!WriteFileNum(col->Red ? 0 : 1, picinfo))
  692.                         return(PIOERR_FILE_ERR);
  693.                     break;
  694.                 case PGM_ASCII:
  695.                     if (!WriteFileNum(col->Red, picinfo))
  696.                         return(PIOERR_FILE_ERR);
  697.                     break;
  698.                 case PPM_ASCII:
  699.                     if (!WriteFileNum(col->Red, picinfo) ||
  700.                         !WriteFileNum(col->Green, picinfo) ||
  701.                         !WriteFileNum(col->Blue, picinfo))
  702.                         return(PIOERR_FILE_ERR);
  703.                     break;
  704.                 case PBM_BINARY:
  705.                     /* write 8 B/W pixels */
  706.                     buff[0] = 0;
  707.                     for (n = 7; n >= 0 && x < w; x++, n--)
  708.                     {
  709.                         col = picinfo->Palette +
  710.                               picinfo->FastReadPix(bmap, x, y);
  711.                         if (col->Red == 0)
  712.                             buff[0] |= 1 << n;
  713.                     }
  714.                     x -= 1;
  715.                     if (!picinfo->WriteFile(buff, 1))
  716.                         return(PIOERR_FILE_ERR);
  717.                     break;
  718.                 case PGM_BINARY:
  719.                     if (!picinfo->WriteFile(&col->Red, 1))
  720.                         return(PIOERR_FILE_ERR);
  721.                     break;
  722.                 case PPM_BINARY:
  723.                     buff[0] = col->Red;
  724.                     buff[1] = col->Green;
  725.                     buff[2] = col->Blue;
  726.                     if (!picinfo->WriteFile(buff, 3))
  727.                         return(PIOERR_FILE_ERR);
  728.                     break;
  729.             }
  730.         }
  731.         if (picinfo->BumpProgress)  /* one more progress requester step */
  732.         {
  733.             if (picinfo->BumpProgress())
  734.                 return(PIOERR_CANCEL);  /* user cancelled */
  735.         }
  736.     }
  737.     if (format == PBM_ASCII || format == PGM_ASCII || format == PPM_ASCII)
  738.     {
  739.         if (!picinfo->WriteFile("\n", 1))  /* add a LF to end the file */
  740.             return(PIOERR_FILE_ERR);
  741.     }
  742.  
  743.     /*  image data successfully saved
  744.      */
  745.     picinfo->ProcessedData |= PCDT_IMAGE;
  746.  
  747.     return(PIOERR_OK);
  748. }
  749.  
  750. __asm void __saveds IOLibCleanup(register __a0 struct PictureInfo *picinfo)
  751. {
  752.     /* no cleanup needed */
  753. }
  754.  
  755. /*
  756.  *  Standard option dispatcher.
  757.  *
  758.  *  This function does not usually need to be changed,
  759.  *  unless the library supports run-time defined options.
  760.  */
  761. static void GetDataOption(struct DataOption *option,
  762.               struct DataOptionEntry *from)
  763. {
  764.     option->Type = from->Type;
  765.     option->UITextStr = from->UITextStr;
  766.     option->Flags = from->Flags;
  767.     option->Value = from->Value;
  768.     option->Min = from->Min;
  769.     option->Max = from->Max;
  770.     option->Default = from->Default;
  771.  
  772.     memcpy(option->String, from->String, sizeof(option->String));
  773.     memset(option->Name, 0, sizeof(option->Name));
  774.     if (from->Name)
  775.         strcpy(option->Name, from->Name);
  776.  
  777.     memset(option->pad, 0, sizeof(option->pad));
  778. }
  779.  
  780. /*
  781.  *  Standard option query function
  782.  *  (support for multiple picture types is included)
  783.  */
  784. __asm BOOL __saveds GetFirstOption(register __a0 struct DataInfo *dinfo,
  785.                    register __a1 struct DataOption *option)
  786. {
  787.     LONG c = dinfo->Code;
  788.  
  789.     if (c < DATA_NUM) {
  790.         DataOptionCount[c] = 0;
  791.         if (DataOptionCount[c] <= DataOptionMax[c])
  792.         {
  793.             GetDataOption(option, Options[c] + DataOptionCount[c]);
  794.             return(TRUE);
  795.         }
  796.     }
  797.     return(FALSE);
  798. }
  799.  
  800. /*
  801.  *  Standard option query function
  802.  *  (support for multiple picture types is included)
  803.  */
  804. __asm BOOL __saveds GetNextOption(register __a0 struct DataInfo *dinfo,
  805.                   register __a1 struct DataOption *option)
  806. {
  807.     LONG c = dinfo->Code;
  808.  
  809.     if (c < DATA_NUM)
  810.     {
  811.         if (DataOptionCount[c] < DataOptionMax[c])
  812.         {
  813.             DataOptionCount[c] += 1;
  814.             GetDataOption(option, Options[c] + DataOptionCount[c]);
  815.             return(TRUE);
  816.         }
  817.     }
  818.     return(FALSE);
  819. }
  820.  
  821. /*
  822.  *  Standard option set function
  823.  *  (support for multiple picture types is included)
  824.  */
  825. __asm void __saveds SetOption(register __a0 struct DataInfo *dinfo,
  826.                   register __a1 struct DataOption *option)
  827. {
  828.     struct DataOptionEntry *opt;
  829.     LONG n, max, c;
  830.  
  831.     c = dinfo->Code;
  832.     if (c < DATA_NUM && option)
  833.     {
  834.         max = DataOptionMax[c];
  835.         /*
  836.          *  find an option with the given name
  837.          */
  838.         for (n = 0, opt = Options[c]; n <= max; n++, opt++)
  839.         {
  840.             if (strcmp(option->Name, opt->Name) == 0) /* found */
  841.             {
  842.                 opt->Value = option->Value;
  843.                 memcpy(opt->String, option->String, sizeof(opt->String));
  844.                 break;
  845.             }
  846.         }
  847.     }
  848. }
  849.  
  850. /*
  851.  *  Standard option reset function
  852.  *  (support for multiple picture types is included)
  853.  */
  854. __asm void __saveds ResetOptions(register __a0 struct DataInfo *dinfo)
  855. {
  856.     struct DataOptionEntry *opt;
  857.     LONG n, max, c;
  858.  
  859.     c = dinfo->Code;
  860.     if (c < DATA_NUM)
  861.     {
  862.         max = DataOptionMax[c];
  863.         for (n = 0, opt = Options[c]; n <= max; n++, opt++)
  864.             opt->Value = opt->Default;
  865.     }
  866. }
  867.  
  868. /*
  869.  *  Private PersonalIO functions
  870.  */
  871. __asm WORD __saveds PersonalIOPrivate1()
  872. {
  873.     return(PIOERR_CANCEL);
  874. }
  875.  
  876. __asm WORD __saveds PersonalIOPrivate2()
  877. {
  878.     return(PIOERR_CANCEL);
  879. }
  880.  
  881. __asm WORD __saveds PersonalIOPrivate3()
  882. {
  883.     return(PIOERR_CANCEL);
  884. }
  885.